﻿Imports System.Xml.Schema
Imports System.Xml
Imports HybrisItemViewer.HybrisItems.Model
Imports System.IO

Namespace HybrisItems

    Public Class ConfigParser

#Region "Vars and Enums"

        Private _XMLDocs As Dictionary(Of String, System.Xml.XmlDocument)
        Private _ValidateResult As ValidateResults = ValidateResults.Unkown
        Private _ValidateResult_lock As New Object

        Private _Model As EntireHybrisSystemModel

        Public XMLDocNames_HybrisModelBin As Dictionary(Of String, EntireHybrisSystemModel.HybrisModelBin)

        Public Enum ValidateResults

            Failed
            Success
            Unkown

        End Enum

#End Region

#Region "Public Properties"

        Public ReadOnly Property XMLDocs As Dictionary(Of String, System.Xml.XmlDocument)
            Get
                If _XMLDocs Is Nothing Then
                    _XMLDocs = New Dictionary(Of String, System.Xml.XmlDocument)()
                End If
                Return _XMLDocs
            End Get
        End Property

        Public Property Model As EntireHybrisSystemModel
            Get
                Return _Model
            End Get
            Set(value As EntireHybrisSystemModel)
                _Model = value
            End Set
        End Property

#End Region

#Region "Private Properties"

        Private Property ValidateResult As ValidateResults
            Get
                SyncLock _ValidateResult_lock
                    Return _ValidateResult
                End SyncLock
            End Get
            Set(value As ValidateResults)
                SyncLock _ValidateResult_lock
                    _ValidateResult = value
                End SyncLock
            End Set
        End Property

#End Region

#Region "XML Functions"

        ''' <summary>
        ''' Loads the supplied XML file into the XMLDoc property
        ''' </summary>
        ''' <param name="Filename"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function LoadXml(Filename As String) As ValidateResults

            ValidateResult = ValidateResults.Unkown

            Dim XmlSettings As New XmlReaderSettings()
            XmlSettings.Schemas.Add("", Application.StartupPath.Trim("\") & "\items.xsd")
            XmlSettings.ValidationType = ValidationType.Schema

            Dim XMLDoc As New System.Xml.XmlDocument
            Dim Xmlr As XmlReader = XmlReader.Create(Filename, XmlSettings)

            Dim ValidateCallBackEvent As New ValidationEventHandler(AddressOf ValidationCallBack)

            Try
                XMLDoc.Load(Xmlr)
                XMLDoc.Validate(ValidateCallBackEvent)

            Catch ex As Exception

                Return ValidateResults.Failed
            Finally

                Xmlr.Close()
            End Try

            XMLDocs.Add(Path.GetFileName(Filename), XMLDoc)

            Return ValidateResults.Success

        End Function

        Private Sub ValidationCallBack(ByVal sender As Object, ByVal args As ValidationEventArgs)

            If args.Exception IsNot Nothing Then
                ValidateResult = ValidateResults.Failed
            Else
                ValidateResult = ValidateResults.Success
            End If

        End Sub

#End Region

#Region "Model Generation"

        Public Function ExtractEntireModel()

            'Clear Current Model
            ClearModel()

            'Loop through each xml config file
            For Each XMLDocKey As String In XMLDocs.Keys

                Dim XMLDoc As XmlDocument = XMLDocs(XMLDocKey)
                XMLDocNames_HybrisModelBin.Add(XMLDocKey, New EntireHybrisSystemModel.HybrisModelBin)

                'extract Atomic types
                ExtractAtomicTypes(XMLDoc, XMLDocKey)

                'extract relations
                ExtractRelations(XMLDoc, XMLDocKey)

                'extract item typess
                ExtractItemTypes(XMLDoc, XMLDocKey)

            Next
            'end loop

            'Wire relations to item types
            Model.Wire()

        End Function

        Public Sub ClearModel()

            Model = New EntireHybrisSystemModel
            XMLDocNames_HybrisModelBin = New Dictionary(Of String, EntireHybrisSystemModel.HybrisModelBin)

        End Sub

        ''' <summary>
        ''' Extracts the relations from the supplied hybris items config file and appends them to the model.Relations collection
        ''' </summary>
        ''' <param name="XmlDoc">Hybris items config file</param>
        ''' <remarks></remarks>
        Public Sub ExtractAtomicTypes(XmlDoc As XmlDocument, XMLDocKey As String)

            'Find all nodes of type relation
            Dim AllNodes As XmlNodeList = XmlDoc.GetElementsByTagName("atomictype")

            Dim Types As Dictionary(Of String, Model.TypeModel) = Model.Types
            Dim AtomicTypes As Dictionary(Of String, Model.AtomicTypeModel) = Model.AtomicTypes

            'Loop through each found node
            For Each Node As XmlNode In AllNodes

                'Create new relation model object from node
                Dim NewItem As New AtomicTypeModel(Node)

                'If the Relation is already in the model then add it to the list of OverWrittenItems.Relations
                If Types.ContainsKey(NewItem.Class.Value) Then
                    Model.OverWrittenItems.Types.Add(NewItem)
                    Types.Remove(NewItem.Class.Value)
                    AtomicTypes.Remove(NewItem.Class.Value)
                End If

                'append new relation model object to Relations object
                Types.Add(NewItem.Class.Value, NewItem)
                AtomicTypes.Add(NewItem.Class.Value, NewItem)

                XMLDocNames_HybrisModelBin(XMLDocKey).Types.Add(NewItem)

            Next
            'end loop

        End Sub

        ''' <summary>
        ''' Extracts the relations from the supplied hybris items config file and appends them to the model.Relations collection
        ''' </summary>
        ''' <param name="XmlDoc">Hybris items config file</param>
        ''' <remarks></remarks>
        Public Sub ExtractRelations(XmlDoc As XmlDocument, XMLDocKey As String)

            'Find all nodes of type relation
            Dim AllNodes As XmlNodeList = XmlDoc.GetElementsByTagName("relation")
            Dim Relations As Dictionary(Of String, Model.RelationModel) = Model.Relations

            'Loop through each found node
            For Each Node As XmlNode In AllNodes

                'Create new relation model object from node
                Dim NewItem As New RelationModel(Node)

                'If the Relation is already in the model then add it to the list of OverWrittenItems.Relations
                If Relations.ContainsKey(NewItem.Code.Value) Then
                    Model.OverWrittenItems.Relations.Add(NewItem)
                    Relations.Remove(NewItem.Code.Value)
                End If

                'append new relation model object to Relations object
                Relations.Add(NewItem.Code.Value, NewItem)

                XMLDocNames_HybrisModelBin(XMLDocKey).Relations.Add(NewItem)

            Next
            'end loop

        End Sub


        ''' <summary>
        ''' Extracts the ItemTypes from the supplied hybris items config file and appends them to the model.ItemTypes collection
        ''' </summary>
        ''' <param name="XmlDoc">Hybris items config file</param>
        ''' <remarks></remarks>
        Public Sub ExtractItemTypes(XmlDoc As XmlDocument, XMLDocKey As String)

            'Find all nodes of type relation 
            Dim AllNodes As XmlNodeList = XmlDoc.GetElementsByTagName("itemtype")

            Dim Types As Dictionary(Of String, Model.TypeModel) = Model.Types
            Dim ItemTypes As Dictionary(Of String, Model.ItemTypeModel) = Model.ItemTypes

            'Loop through each found node
            For Each Node As XmlNode In AllNodes

                'Create new relation model object from node
                Dim NewItem As New ItemTypeModel(Node)

                'If the itemType is already in the model then add it to the list of OverWrittenItems.ItemTypes
                If Types.ContainsKey(NewItem.Code.Value) Then
                    Model.OverWrittenItems.Types.Add(NewItem)
                    Types.Remove(NewItem.Code.Value)
                    ItemTypes.Remove(NewItem.Code.Value)
                End If

                'append new itemtype model object to ItemTypes object
                Types(NewItem.Code.Value) = NewItem

                XMLDocNames_HybrisModelBin(XMLDocKey).Types.Add(NewItem)

            Next
            'end loop

        End Sub

#End Region

#Region "Misc"

        ''' <summary>
        ''' Get the attribute from the supplied node. if does not exist then will use the DefaultValue
        ''' </summary>
        ''' <param name="Node"></param>
        ''' <param name="Name"></param>
        ''' <param name="DefaultValue"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function GetAttribute(Node As XmlNode, Name As String, Optional DefaultValue As String = "")

            Dim Attribute As XmlAttribute = Node.Attributes(Name)
            If Attribute Is Nothing Then
                Return (DefaultValue)
            Else
                Return Attribute.Value
            End If

        End Function

#End Region

    End Class

End Namespace